package checker

import (
	"kumachan/interpreter/lang/ast"
	"kumachan/interpreter/lang/common/name"
	"kumachan/interpreter/lang/common/source"
	"kumachan/interpreter/compiler/loader"
	"kumachan/interpreter/compiler/checker/typsys"
	"kumachan/interpreter/compiler/checker/checked"
)


type Program struct {
	EntryPath  string
	Functions  [] ProgramFunction
	*ProgramInfo
}
type ProgramFunction struct {
	Name      name.FunctionName
	Body      FunctionBody
	IsThunk   bool
	IsEffect  bool
	Location  source.Location
}
type ProgramInfo struct {
	*Registry
	*ModuleInfo
	DispatchMapping
	*RpcInfo
}

func TypeCheck(entry *loader.Module) (*Program, source.Errors) {
	var mi, mic = collectModuleInfo(entry)
	var sc = collectSectionMapping(entry)
	var al, err1 = collectAlias(entry, mic, sc)
	if err1 != nil { return nil, err1 }
	var tr, tl, err2 = collectTypes(entry, mic, sc, al)
	if err2 != nil { return nil, err2 }
	var fr, fl, dm, ri, err3 = collectFunctions(entry, mic, sc, al, tr, tl)
	if err3 != nil { return nil, err3 }
	var reg = &Registry {
		Aliases:   al,
		Types:     tr,
		Functions: fr,
	}
	var info = &ProgramInfo {
		Registry:        reg,
		ModuleInfo:      mi,
		DispatchMapping: dm,
		RpcInfo:         ri,
	}
	var is_in_entry_mod = func(f *Function) bool {
		return (f.Name.ModuleName == mi.ModName)
	}
	var functions = make([] ProgramFunction, len(fl))
	for i, f := range fl {
		functions[i] = ProgramFunction {
			Name: f.Name,
			Body: f.Body,
			IsThunk:  (f.AstNode.Kind == ast.FK_Constant),
			IsEffect: ((f.AstNode.Kind == ast.FK_Do) && is_in_entry_mod(f)),
			Location: f.Location,
		}
	}
	var program = &Program {
		EntryPath:   entry.Path,
		Functions:   functions,
		ProgramInfo: info,
	}
	return program, nil
}

func TypeCheckStandaloneExpr (
	expected  typsys.Type,
	node      ast.Expr,
	program   *Program,
	local     (map[string] *checked.LocalBinding),
) (*checked.Expr, *source.Error) {
	var ctx = ExprContext {
		ExprContextBase: &ExprContextBase {
			Registry:        program.Registry,
			ModuleInfo:      program.ModuleInfo,
			ParameterList:   [] typsys.Parameter {},
			DispatchMapping: program.DispatchMapping,
		},
		LocalBindingMap: local,
	}
	var expr, _, err = check(node)(expected, nil, ctx)
	return expr, err
}


